// similar to unzipChunk above but slices (0,minv.dataPosition) and (maxv.dataPosition,end) off
import 'dart:io';
import 'dart:typed_data';

import 'package:archive/archive.dart';
import 'package:dbio_utils/base/beans.dart';
import 'package:dbio_utils/tabix/chunk.dart';

// import 'package:dpako/inflate.dart' as ifl;
// import 'package:dpako/zlib/constants.dart' show Z_SYNC_FLUSH;
// import 'package:dpako/zlib/zstream.dart';

class ChunkSlice extends MapBean {
  ChunkSlice([Map map]) : super(map);

  Chunk get chunk => this['chunk'];
  List<int> get buffer => this['buffer'].map<int>((e) => e as int).toList();
  List<int> get cpositions => this['cpositions'].map<int>((e) => e as int).toList();
  List<int> get dpositions => this['dpositions'].map<int>((e) => e as int).toList();
}

List<int> unzip(Uint8List bytes, {bool verify = false}) {
  return GZipDecoder().decodeBytes(bytes, verify: verify);
}

ChunkSlice unzipChunkSlice(List<int> inputData, Chunk chunk) {
  return unzipChunkSliceIGV(inputData, chunk);
}

// ChunkSlice unzipChunkSlicePkao(List<int> inputData, Chunk chunk) {
//   try {
//     ZStream strm;
//     var cpos = chunk.minv.blockPosition;
//     var dpos = chunk.minv.dataPosition;
//     List<List<int>> decompressedBlocks = [];
//     List cpositions = [];
//     List dpositions = [];
//     do {
//       var remainingInput = inputData.sublist(cpos - chunk.minv.blockPosition);
//
//       // List<int> _bytes = ZLibDecoder().decodeBytes(remainingInput);
//
//       var inflator = ifl.Inflate();
//       // List<int> _bytes = inflator.getBytes();
//
//       strm = inflator.strm;
//       inflator.push(remainingInput, Z_SYNC_FLUSH);
//       if (inflator.err != 0) throw Exception(inflator.msg);
//
//       // @ts-ignore
//       // Uint8List buffer = inflator.getBytes();
//       // ByteBuffer _buffer = Uint8List.fromList(_bytes).buffer;
//
//       List<int> _bytes = inflator.result;
//
//       decompressedBlocks.add(_bytes);
//       var len = _bytes.length;
//
//       cpositions.add(cpos);
//       dpositions.add(dpos);
//       if (decompressedBlocks.length == 1 && chunk.minv.dataPosition > 0) {
//         // this is the first chunk, trim it
//         decompressedBlocks[0] = decompressedBlocks[0].sublist(chunk.minv.dataPosition);
//         len = decompressedBlocks[0].length;
//       }
//       var origCpos = cpos;
//       cpos += 0; //strm.next_in;
//       dpos += len;
//
//       if (origCpos >= chunk.maxv.blockPosition) {
//         // this is the last chunk, trim it and stop decompressing
//         // note if it is the same block is minv it subtracts that already
//         // trimmed part of the slice length
//
//         decompressedBlocks[decompressedBlocks.length - 1] = decompressedBlocks[decompressedBlocks.length - 1].sublist(
//           0,
//           chunk.maxv.blockPosition == chunk.minv.blockPosition //
//               ? chunk.maxv.dataPosition - chunk.minv.dataPosition + 1
//               : chunk.maxv.dataPosition + 1,
//         );
//
//         cpositions.add(cpos);
//         dpositions.add(dpos);
//         break;
//       }
//     } while (strm?.avail_in ?? 0 > 0);
//     var buffer = List<int>();
//     for (List<int> p in decompressedBlocks) {
//       buffer.addAll(p);
//     }
//     return ChunkSlice({
//       'buffer': buffer,
//       'cpositions': cpositions,
//       'dpositions': dpositions,
//     });
//   } catch (e) {
//     // if (RegExp('incorrect header check').hasMatch(e.message)) {
//     //   throw new Exception(
//     //     'problem decompressing block: incorrect gzip header check',
//     //   );
//     // }
//     throw e;
//   }
// }

ChunkSlice unzipChunkSliceIGV(List<int> inputData, Chunk chunk) {
  List<List<int>> oBlockList = [];
  // var ptr = 0;
  var totalSize = 0;

  var cpos = chunk.minv.blockPosition;
  var dpos = chunk.minv.dataPosition;
  List cpositions = [];
  List dpositions = [];
  var lim = inputData.length - 18;

  while (cpos < lim) {
    try {
      var ba = inputData.sublist(cpos, cpos + 18);

      var xlen = (ba[11] << 8) | (ba[10]);
      var si1 = ba[12];
      var si2 = ba[13];
      var slen = (ba[15] << 8) | (ba[14]);
      var bsize = ((ba[17] << 8) | (ba[16])) + 1;
      var start = 12 + xlen + cpos; // Start of CDATA
      var bytesLeft = inputData.length - start;
      var cDataSize = bsize - xlen - 19;
      if (bytesLeft < cDataSize || cDataSize <= 0) break;

      // var a = new Uint8Array(data, start, cDataSize);
      // var inflate = new Zlib.RawInflate(a);
      // var unc = inflate.decompress();
      var remainingInput = inputData.sublist(start, start + cDataSize);
      // List<int> _bytes = ZLibDecoder().decodeBytes(remainingInput);
      Inflate inflate = Inflate(remainingInput);
      List<int> _bytes = inflate.getBytes();

      cpositions.add(cpos);
      dpositions.add(dpos);

      cpos += (inflate.input.position) + 26;
      dpos += _bytes.length;
      totalSize += _bytes.length;
      oBlockList.add(_bytes);
    } catch (e) {
      print(e);
      break;
    }
  }
  var buffer = List<int>();
  for (List<int> p in oBlockList) {
    buffer.addAll(p);
  }
  return ChunkSlice({
    'buffer': buffer,
    'cpositions': cpositions,
    'dpositions': dpositions,
  });
}
